package com.xc.ezplan.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xc.ezplan.admin.entity.AdminDept;
import com.xc.ezplan.admin.entity.AdminRolesDepts;
import com.xc.ezplan.admin.mapper.AdminRolesDeptsMapper;
import com.xc.ezplan.admin.service.AdminDeptService;
import com.xc.ezplan.admin.mapper.AdminDeptMapper;
import com.xc.ezplan.admin.vo.AdminDeptVo;
import com.xc.ezplan.cache.constants.RedisKey;
import com.xc.ezplan.cache.utils.CacheUtil;
import com.xc.ezplan.cache.utils.RedisUtils;
import com.xc.ezplan.core.base.SearchCondition;
import com.xc.ezplan.core.exception.BadRequestException;
import com.xc.ezplan.core.utils.FileUtil;
import com.xc.ezplan.core.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author lixingchen
 * @date 2022/11/19
 * @description 部门管理实现类
 */
@Service
@Primary
@RequiredArgsConstructor
@CacheConfig(cacheNames = "dept")
public class AdminDeptServiceImpl extends ServiceImpl<AdminDeptMapper, AdminDept> implements AdminDeptService {

	private final AdminDeptMapper adminDeptMapper;
	private final AdminRolesDeptsMapper adminRolesDeptsMapper;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void createDept(AdminDeptVo adminDeptVo) {
		AdminDept adminDept = new AdminDept();
		BeanUtils.copyProperties(adminDeptVo, adminDept);
		adminDeptMapper.insert(adminDept);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteDept(Set<Long> ids) {
		for (Long id : ids) {
			if (adminDeptMapper.selectCount(new QueryWrapper<AdminDept>().lambda().eq(AdminDept::getPid, id)) > 0) {
				throw new BadRequestException("操作的部门存在子部门,不能删除");
			} else if (adminRolesDeptsMapper
					.selectCount(new QueryWrapper<AdminRolesDepts>().lambda().eq(AdminRolesDepts::getDeptId, id)) > 0) {
				throw new BadRequestException("操作的部门存在与角色关联,不能删除");
			}
		}
		adminDeptMapper.delete(new QueryWrapper<AdminDept>().lambda().in(AdminDept::getId, ids));
		CacheUtil.deleteCache(RedisKey.DEPT_ID,ids);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateDept(AdminDeptVo adminDeptVo) {
		if (adminDeptVo.getPid() != null && adminDeptVo.getId().equals(adminDeptVo.getPid())) {
			throw new BadRequestException("上级不能为自己");
		}
		AdminDept adminDept = new AdminDept();
		BeanUtils.copyProperties(adminDeptVo, adminDept);
		adminDeptMapper.update(adminDept,
				new UpdateWrapper<AdminDept>().lambda().eq(AdminDept::getId, adminDept.getId()));
		CacheUtil.deleteCache(RedisKey.DEPT_ID,adminDeptVo.getId());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void exportDept(HttpServletResponse response, List<Long> ids) throws IOException {
		List<AdminDept> adminDepts = adminDeptMapper
				.selectList(new QueryWrapper<AdminDept>().lambda().in(AdminDept::getId, ids));
		List<Map<String, Object>> list = new ArrayList<>();
		for (AdminDept deptDTO : adminDepts) {
			Map<String, Object> map = new LinkedHashMap<>();
			map.put("部门名称", deptDTO.getName());
			map.put("部门状态", deptDTO.getEnabled() ? "启用" : "停用");
			map.put("创建日期", deptDTO.getCreateTime());
			list.add(map);
		}
		FileUtil.downloadExcel(list);
	}

	@Override
	@Cacheable(key = "'id:' + #p0")
	public Object queryDept(Long deptId) {
		AdminDeptVo adminDeptVo = new AdminDeptVo();
		adminDeptVo.setDeptList(adminDeptMapper.selectList(null));
		if (deptId != null) {
			AdminDept adminDept = adminDeptMapper.selectById(deptId);
			BeanUtils.copyProperties(adminDept, adminDeptVo);
		}
		return adminDeptVo;
	}

	@Override
	public Object pageQueryDept(SearchCondition searchCondition, Page<AdminDept> page) {
		List<Date> createTime = searchCondition.getCreateTime();
		LambdaQueryWrapper<AdminDept> queryWrapper = new QueryWrapper<AdminDept>().lambda().like(
				StringUtils.isNotBlank(searchCondition.getKeyWord()), AdminDept::getName, searchCondition.getKeyWord());
		if (!CollectionUtils.isEmpty(createTime) && createTime.size() == 2) {
			queryWrapper.between(AdminDept::getCreateTime, createTime.get(0), createTime.get(1));
		}
		Page<AdminDept> adminDeptPage = adminDeptMapper.selectPage(page, queryWrapper);
		List<AdminDept> records = adminDeptPage.getRecords();
		adminDeptPage.setRecords(listWithTree(records));
		return adminDeptPage;
	}

	private List<AdminDept> listWithTree(List<AdminDept> list) {
		List<AdminDept> collect = list.stream()
				// 2. 找出所有顶级（规定 0 为顶级）
				.filter(o -> Objects.equals(0L, o.getPid()))
				// 3.给当前父级的 childList 设置子
				.peek(o -> o.setChildren(getChildList(o, list)))
				// 4.收集
				.collect(Collectors.toList());
		return collect;
	}

	/**
	 * 根据当前父类 找出子类， 并通过递归找出子类的子类
	 *
	 * @param  adminDept:
	 * @param  list:
	 * @return : List<AdminDept>
	 */
	private List<AdminDept> getChildList(AdminDept adminDept, List<AdminDept> list) {
		return list.stream()
				// 筛选出父节点id == parentId 的所有对象 => list
				.filter(o -> Objects.equals(adminDept.getId(), o.getPid())).peek(o -> o.setChildren(getChildList(o, list)))
				.collect(Collectors.toList());
	}

}
